# finance_system.py
import json
from datetime import date, timedelta
from django.db import models
from django.http import JsonResponse
from django.views import View
from django.urls import path
from django.core.validators import MinValueValidator
from django.core.exceptions import ValidationError


# ==================== 数据模型 ====================
class Transaction(models.Model):
    PAYMENT_TYPES = [
        ('cash', '现金'),
        ('card', '银行卡'),
        ('mobile', '移动支付'),
    ]

    amount = models.DecimalField(
        max_digits=12,
        decimal_places=2,
        validators=[MinValueValidator(0.01)]
    )
    payment_type = models.CharField(max_length=20, choices=PAYMENT_TYPES)
    timestamp = models.DateTimeField(auto_now_add=True)
    tax_amount = models.DecimalField(max_digits=12, decimal_places=2)
    is_refund = models.BooleanField(default=False)

    def clean(self):
        if self.amount < 0:
            raise ValidationError("交易金额不能为负数")


class Budget(models.Model):
    CATEGORIES = [
        ('marketing', '市场推广'),
        ('hr', '人力资源'),
        ('rd', '研发'),
    ]

    category = models.CharField(max_length=20, choices=CATEGORIES)
    amount = models.DecimalField(max_digits=12, decimal_places=2)
    start_date = models.DateField()
    end_date = models.DateField()
    actual_spending = models.DecimalField(max_digits=12, decimal_places=2, default=0)

    @property
    def remaining(self):
        return self.amount - self.actual_spending


class TaxRate(models.Model):
    TAX_TYPES = [
        ('vat', '增值税'),
        ('income', '所得税'),
    ]

    tax_type = models.CharField(max_length=20, choices=TAX_TYPES, unique=True)
    rate = models.DecimalField(max_digits=5, decimal_places=2)  # 存储百分比值
    effective_date = models.DateField()


# ==================== 业务逻辑 ====================
class FinanceService:
    @staticmethod
    def generate_daily_report():
        today = date.today()
        transactions = Transaction.objects.filter(timestamp__date=today)

        return {
            'total_income': sum(t.amount for t in transactions if not t.is_refund),
            'total_refunds': sum(t.amount for t in transactions if t.is_refund),
            'total_tax': sum(t.tax_amount for t in transactions)
        }

    @staticmethod
    def calculate_budget_status():
        budgets = Budget.objects.all()
        return [{
            'category': b.category,
            'allocated': b.amount,
            'used': b.actual_spending,
            'remaining': b.remaining
        } for b in budgets]


# ==================== API视图 ====================
class TransactionAPI(View):
    def post(self, request):
        try:
            data = json.loads(request.body)
            tax_rate = TaxRate.objects.get(tax_type='vat').rate / 100
            tax_amount = data['amount'] * tax_rate

            Transaction.objects.create(
                amount=data['amount'],
                payment_type=data['payment_type'],
                tax_amount=tax_amount,
                is_refund=data.get('is_refund', False)
            )
            return JsonResponse({'status': 'success'}, status=201)

        except TaxRate.DoesNotExist:
            return JsonResponse({'error': '税率未配置'}, status=400)
        except KeyError as e:
            return JsonResponse({'error': f'缺少必要字段: {e}'}, status=400)


class ReportAPI(View):
    def get(self, request):
        report_type = request.GET.get('type', 'daily')

        if report_type == 'daily':
            report = FinanceService.generate_daily_report()
            return JsonResponse(report)

        return JsonResponse({'error': '不支持的报表类型'}, status=400)


class BudgetAPI(View):
    def post(self, request):
        try:
            data = json.loads(request.body)
            Budget.objects.create(**data)
            return JsonResponse({'status': 'created'}, status=201)

        except ValidationError as e:
            return JsonResponse({'error': str(e)}, status=400)


# ==================== 路由配置 ====================
urlpatterns = [
    path('transactions/', TransactionAPI.as_view()),
    path('reports/', ReportAPI.as_view()),
    path('budgets/', BudgetAPI.as_view()),
]

# ==================== 单元测试 ====================
import pytest
from django.test import RequestFactory
from django.urls import reverse
from .models import Transaction, Budget, TaxRate


@pytest.mark.django_db
class TestFinanceSystem:
    def setup_method(self):
        self.factory = RequestFactory()
        TaxRate.objects.create(tax_type='vat', rate=16.0)

    def test_create_transaction(self):
        request = self.factory.post('/transactions/', {
            'amount': 100.00,
            'payment_type': 'cash'
        }, content_type='application/json')

        response = TransactionAPI.as_view()(request)
        assert response.status_code == 201
        assert Transaction.objects.count() == 1

    def test_daily_report(self):
        Transaction.objects.create(
            amount=200.00,
            payment_type='card',
            tax_amount=32.00
        )

        request = self.factory.get('/reports/?type=daily')
        response = ReportAPI.as_view()(request)

        assert response.status_code == 200
        assert json.loads(response.content)['total_income'] == '200.00'

    def test_budget_creation(self):
        data = {
            'category': 'marketing',
            'amount': 50000.00,
            'start_date': '2024-01-01',
            'end_date': '2024-12-31'
        }

        request = self.factory.post('/budgets/',
                                    data=json.dumps(data),
                                    content_type='application/json'
                                    )

        response = BudgetAPI.as_view()(request)
        assert response.status_code == 201
        assert Budget.objects.count() == 1


@pytest.fixture(scope='module')
def django_db_setup():
    from django.conf import settings
    settings.DATABASES['default'] = {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': ':memory:'
    }


# ==================== 运行配置 ====================
if __name__ == "__main__":
    from django.core.management import execute_from_command_line

    execute_from_command_line(['manage.py', 'runserver'])